/**
 * Pxb Utility
 * Copyright (C) 2009 Panxiaobo.
 * $Id$
 */
package pxb.util.http.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author Panxiaobo
 * 
 */
public class SimpleHttpConnectorImpl extends AbstractConnector {
    private static class ResponseImpl implements HttpResponse {
        private HttpURLConnection connection;

        /**
         * @param connection
         */
        private ResponseImpl(HttpURLConnection connection) {
            super();
            this.connection = connection;
        }

        /*
         * (non-Javadoc)
         * 
         * @see pxb.util.http.HttpConnector.HttpResponse#close()
         */
        public void close() throws IOException {
            connection.disconnect();
        }

        /*
         * (non-Javadoc)
         * 
         * @see pxb.util.http.HttpConnector.HttpResponse#getHead(java.lang.String)
         */
        public String getHead(String head) throws IOException {
            return connection.getHeaderField(head);
        }

        /*
         * (non-Javadoc)
         * 
         * @see pxb.util.http.HttpConnector.HttpResponse#getInputStream()
         */
        public InputStream getInputStream() throws IOException {
            return connection.getInputStream();
        }

        /*
         * (non-Javadoc)
         * 
         * @see pxb.util.http.HttpConnector.HttpResponse#getStatus()
         */
        public int getStatus() throws IOException {
            return connection.getResponseCode();
        }

    }

    private String charactSet = "UTF-8";

    /**
     * @return the charactSet
     */
    public String getCharactSet() {
        return charactSet;
    }

    /**
     * @param charactSet
     *            the charactSet to set
     */
    public void setCharactSet(String charactSet) {
        this.charactSet = charactSet;
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.util.http.HttpConnector#get(java.lang.String, java.util.Map, java.util.Map)
     */
    public HttpResponse get(String url, Map<String, String> headers, Map<String, String> parameters) throws IOException {
        if (null == url || "".equals(url)) {
            throw new IllegalArgumentException("URL Should NOT Empty");
        }
        if (parameters != null) {
            StringBuilder sb = new StringBuilder(url);
            Iterator<Map.Entry<String, String>> it = parameters.entrySet().iterator();
            if (it.hasNext()) {
                Map.Entry<String, String> entry = it.next();
                if (url.indexOf('/', 8) < 0) {
                    sb.append('/');
                }
                sb.append(url.indexOf('?') < 0 ? '?' : '&').append(URLEncoder.encode(entry.getKey(), this.charactSet))
                        .append('=').append(URLEncoder.encode(entry.getValue(), this.charactSet));
                while (it.hasNext()) {
                    entry = it.next();
                    sb.append('&').append(URLEncoder.encode(entry.getKey(), this.charactSet)).append('=')
                            .append(URLEncoder.encode(entry.getValue(), this.charactSet));
                }
            }

            url = sb.toString();
        }
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("GET");
        if (headers != null) {
            for (Map.Entry<?, ?> entry : headers.entrySet()) {
                connection.setRequestProperty(entry.getKey().toString(), entry.getValue().toString());
            }
        }

        // connection.setDoOutput(true);
        connection.connect();
        return new ResponseImpl(connection);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.util.http.HttpConnector#post(java.lang.String, java.util.Map, java.util.Map)
     */
    public HttpResponse post(String url, Map<String, String> headers, Map<String, String> parameters)
            throws IOException {
        if (null == url || "".equals(url)) {
            throw new IllegalArgumentException("URL Should NOT Empty");
        }
        StringBuilder sb = new StringBuilder();
        if (parameters != null) {
            for (Map.Entry<String, String> entry : parameters.entrySet()) {
                sb.append('&').append(URLEncoder.encode(entry.getKey(), this.charactSet)).append('=')
                        .append(URLEncoder.encode(entry.getValue(), this.charactSet));
            }
        }
        Map<String, String> selfMap = headers == null ? new HashMap<String, String>() : new HashMap<String, String>(
                headers);
        // selfMap.put("Content-Type", "x-www-form-urlencoded;charset=" + this.charactSet);
        return post(url, selfMap, sb.substring(1).getBytes());
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.util.http.HttpConnector#post(java.lang.String, java.util.Map, byte[])
     */
    public HttpResponse post(String url, Map<String, String> headers, byte[] data) throws IOException {
        if (null == url || "".equals(url)) {
            throw new IllegalArgumentException("URL Should NOT Empty");
        }
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("POST");
        if (headers != null) {
            for (Map.Entry<?, ?> entry : headers.entrySet()) {
                connection.setRequestProperty(entry.getKey().toString(), entry.getValue().toString());
            }
        }
        if (data != null) {
            // connection.setRequestProperty("Content-Length", String.valueOf(data.length));
            OutputStream out = null;
            try {
                connection.setDoOutput(true);
                out = connection.getOutputStream();
                out.write(data);
                out.flush();
            } finally {
                if (out != null)
                    out.close();
            }
        }
        connection.connect();
        return new ResponseImpl(connection);
    }

}
